﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using NetWork.Packets;
using NetWork.Packets.Factory;

namespace NetWork.Layer
{
    public class HTTPManager
    {
        private string name;

        public string Name
        {
            get
            {
                return name;
            }
        }

        private Queue<Packet> sendDatas = new Queue<Packet>();
        private Queue<Packet> receivedDatas = new Queue<Packet>();
        private Queue<HttpHandler> handlers = new Queue<HttpHandler>();
        private Queue<NET_RESULT_TYPE> results = new Queue<NET_RESULT_TYPE>();
        private HttpUtil httpUtil = null;
        private static HTTPManager instance = null;
        private bool sending = false;
        private Packet m_kLastSendPacket = null;
        private byte[] m_arrLastSendPacket = null;
        private HttpHandler m_dLastSendHandler = null;

        private Queue<Packet> externalDatas = new Queue<Packet>();

        public static HTTPManager Instance { get { return instance; } }

        public static HTTPManager Init(string url, string httpName)
        {
            instance = new HTTPManager(httpName);
            instance.SetServerUrl(url);
            return instance;
        }

        public static void ResetHttp()
        {
            instance = null;
        }

        public HTTPManager(string name)
        {
            this.name = name;
        }

        public void SetServerUrl(string url)
        {
            httpUtil = new HttpUtil(url, this);
        }

        public void ReconnectServer(string url)
        {
            httpUtil = new HttpUtil(url, this);
        }

        public bool Send(Packet pbwh, HttpHandler successHandler)
        {
            if (sending)
            {
                return false;
            }
            // Send Http Packet, Show Net Wait Box
            //UnityEngine.Debug.Log("###########"+pbwh.nOpCode);
            //UnityEngine.Debug.Log("###########" + Newtonsoft.Json.JsonConvert.SerializeObject(pbwh.kBody));
            //UnityEngine.Debug.Log("###########" + UnityEngine.JsonUtility.ToJson(pbwh.kBody));
            NetAPI.ShowNetWaitBox();
            byte[] msg;
            if (PacketFactory.WebPB2Bytes(pbwh.nOpCode, pbwh.kBody, out msg) && httpUtil.Send(msg))
            {
                sendDatas.Enqueue(pbwh);
                handlers.Enqueue(successHandler);
                m_kLastSendPacket = pbwh;
                m_dLastSendHandler = successHandler;
                int nLength = msg.Length;
                m_arrLastSendPacket = new byte[nLength];
                Buffer.BlockCopy(msg, 0, m_arrLastSendPacket, 0, nLength);
                UnityEngine.Debug.LogWarning("[PACKET] Tomsg :" + pbwh.nOpCode);
                return true;
            }
            else
            {
                return false;
            }
        }
        

        public bool Send(int id, Object pbData, HttpHandler successHandler)
        {
            return Send(new Packet(id, pbData), successHandler);
        }

        public bool ResendTimeOut()
        {
            if (sending)
            {
                return false;
            }
            if (httpUtil.Send(m_arrLastSendPacket))
            {
                NetAPI.ShowNetWaitBox();
                sendDatas.Enqueue(m_kLastSendPacket);
                handlers.Enqueue(m_dLastSendHandler);
                return true;
            }
            else
            {
                return false;
            }
        }

        public void SessionCompleted(bool success, byte[] data = null)
        {
            if (!success)
            {
                Enqueue<NET_RESULT_TYPE>(results, NET_RESULT_TYPE.NET_ERROR_TIMEOUT);
                UnityEngine.Debug.LogError("Msg Error: 网络链接超时");
            }
            else
            {
                try
                {
                    int id;
                    object pbData;
                    List<Packet> externalPacks;
                    if (PacketFactory.WebBytes2PB(data, out id, out pbData, out externalPacks))
                    {
#if UNITY_EDITOR
                        UnityEngine.Debug.LogWarning("Receive http packet " + id);
#endif
                        Enqueue<Packet>(receivedDatas, new Packet(id, pbData));
                        Enqueue<NET_RESULT_TYPE>(results, NET_RESULT_TYPE.NET_SUCCESS);
                        foreach (var packet in externalPacks)
                        {
                            Enqueue<Packet>(externalDatas, packet);
                        }
                    }
                    else
                    {
                        Enqueue<NET_RESULT_TYPE>(results, NET_RESULT_TYPE.NET_ERROR_MSGFORMAT);
                    }
                }
                catch (Exception e)
                {
                    Enqueue<NET_RESULT_TYPE>(results, NET_RESULT_TYPE.NET_ERROR_TRANSLATE);
                    UnityEngine.Debug.LogError("Msg Error: 数据转换错误 " + e);
                }
            }
            sending = false;
        }

        internal void Tick()
        {
            while (results.Count > 0)
            {
                NetAPI.CleanNetBox();
                NET_RESULT_TYPE eType = Dequeue<NET_RESULT_TYPE>(results);

                Packet pbs = Dequeue<Packet>(sendDatas);
                HttpHandler handler = Dequeue<HttpHandler>(handlers);
                if (eType == NET_RESULT_TYPE.NET_SUCCESS)
                {
                    Packet pbw = Dequeue<Packet>(receivedDatas);
                    if (pbw.nOpCode == ProtoBuf.Message.OpDefine.ErrorMessage)
                    {
                        ProtoBuf.Message.ErrorMessage errorMsg = pbw.kBody as ProtoBuf.Message.ErrorMessage;
                        UnityEngine.Debug.LogError("Http Server Msg Error,code: " + errorMsg.code + " msg:" + errorMsg.msg);
                        if(int.Parse(errorMsg.code)==21)
                        {
                            BoxManager.CreateReloginBox(errorMsg.msg);
                            break;
                        }
                        BoxManager.CreateNetError(errorMsg.msg);
                        handler(pbw,false);
                        return;
                    }
                    if (pbw != null)
                    {
                        handler(pbw, true);
                    }
                }
                else
                {
                    HttpError(pbs, handler, eType);
                }
            }
            while (externalDatas.Count > 0)
            {
                Packet pbs = Dequeue<Packet>(externalDatas);
                if (pbs.nOpCode == ProtoBuf.Message.OpDefine.SCPlayer)
                {
                    StaticData.playerData.RefreshData((ProtoBuf.Message.SCPlayer)pbs.kBody);
                }
            }
        }

        public void CleanCatch()
        {
            sendDatas.Clear();
            receivedDatas.Clear();
            results.Clear();
            handlers.Clear();
        }

        private void Enqueue<T>(Queue<T> queue, T element)
        {
            lock (queue)
            {
                queue.Enqueue(element);
            }
        }

        private T Dequeue<T>(Queue<T> queue)
        {
            lock (queue)
            {
                return queue.Dequeue();
            }
        }

        public void HttpError(Packet pbwh, HttpHandler retryHandler, NET_RESULT_TYPE eErrorType)
        {
            //可以写代码由用户控制是否重新发送
            m_kLastSendPacket = pbwh;
            m_dLastSendHandler = retryHandler;
            if (eErrorType == NET_RESULT_TYPE.NET_ERROR_TIMEOUT)
            {
                UnityEngine.Debug.LogError("Mask time over");
                if (this == instance)
                {
                    NetAPI.ShowNetTimeOutBox();
                }
                else
                {
                    retryHandler(pbwh, false);
                }
            }
            else if (eErrorType == NET_RESULT_TYPE.NET_ERROR_MSGFORMAT)
            {
                UnityEngine.Debug.LogError("传输协议格式异常");
                NetAPI.ShowNetErrorBox(LanguageTool.GetTextNoUpdate(1002));
                retryHandler(pbwh, false);
            }
            else if (eErrorType == NET_RESULT_TYPE.NET_ERROR_TRANSLATE)
            {
                //UnityEngine.Debug.LogError("Message Translate Error: 服务器通信协议异常！请检查通信协议是否为最新");
                NetAPI.ShowNetErrorBox(LanguageTool.GetTextNoUpdate(1003));
                retryHandler(pbwh, false);
            }
            UnityEngine.Debug.LogError("Msg Error: " + pbwh.nOpCode);
        }

        public enum NET_RESULT_TYPE
        {
            NET_SUCCESS,
            NET_ERROR_TIMEOUT,
            NET_ERROR_MSGFORMAT,
            NET_ERROR_TRANSLATE,
        }

        public bool isSending()
        {
            return sending;
        }
    }

    public delegate void HttpHandler(Packet receiveData, bool bSuccess);
}